FrameLib  2.0
DSP processing with frames of arbitrary timing and length
FrameLib_Threading.h
Go to the documentation of this file.
1 
2 #ifndef FrameLib_THREADING_H
3 #define FrameLib_THREADING_H
4 
5 #include "FrameLib_Types.h"
6 
7 #include <atomic>
8 
15 #ifdef __linux__
16 
17 // Linux specific definitions
18 
19 #include <pthread.h>
20 #include <semaphore.h>
21 
22 namespace OS_Specific
23 {
24  typedef pthread_t OSThreadType;
25  typedef sem_t OSSemaphoreType;
26  typedef void *OSThreadFunctionType(void *arg);
27 }
28 
29 #elif defined(__APPLE__)
30 
31 // OSX specific definitions
32 
33 #include <pthread.h>
34 #include <mach/mach.h>
35 
36 namespace OS_Specific
37 {
38  typedef pthread_t OSThreadType;
39  typedef semaphore_t OSSemaphoreType;
40  typedef void *OSThreadFunctionType(void *arg);
41 }
42 
43 #else
44 
45 // Windows OS specific definitions
46 
47 #include <windows.h>
48 
49 namespace OS_Specific
50 {
51  typedef HANDLE OSThreadType;
52  typedef HANDLE OSSemaphoreType;
53  typedef DWORD WINAPI OSThreadFunctionType(LPVOID arg);
54 }
55 
56 #endif
57 
58 // Helpers for exchange fixed values with atomic types
59 
60 template <class T>
61 bool compareAndSwap(std::atomic<T>& value, T comparand, T exchange)
62 {
63  return value.compare_exchange_strong(comparand, exchange);
64 }
65 
66 template <class T>
67 bool nullSwap(std::atomic<T *>& value, T *exchange)
68 {
69  T *comparand = nullptr;
70  return value.compare_exchange_strong(comparand, exchange);
71 }
72 
73 
85 {
86 
87 public:
88 
89  FrameLib_SpinLock() : mAtomicLock(false) {}
90  ~FrameLib_SpinLock() { acquire(); }
91 
92  // Non-copyable
93 
94  FrameLib_SpinLock(const FrameLib_SpinLock&) = delete;
95  FrameLib_SpinLock& operator=(const FrameLib_SpinLock&) = delete;
96 
97  bool attempt() { return compareAndSwap(mAtomicLock, false, true); }
98  void acquire() { while(attempt() == false); }
99  void release() { compareAndSwap(mAtomicLock, true, false); }
100 
101 private:
102 
103  std::atomic<bool> mAtomicLock;
104 };
105 
106 
118 {
119 
120 public:
121 
122  FrameLib_SpinLockHolder(FrameLib_SpinLock *lock) : mLock(lock) { if (mLock) mLock->acquire(); }
123  ~FrameLib_SpinLockHolder() { if (mLock) mLock->release(); }
124 
125  // Non-copyable
126 
128  FrameLib_SpinLockHolder& operator=(const FrameLib_SpinLockHolder&) = delete;
129 
130  void destroy()
131  {
132  if (mLock)
133  mLock->release();
134  mLock = nullptr;
135  }
136 
137 private:
138 
139  FrameLib_SpinLock *mLock;
140 };
141 
142 
156 {
157  typedef void ThreadFunctionType(void *);
158 
159 public:
160 
161  enum PriorityLevel {kLowPriority, kMediumPriority, kHighPriority, kAudioPriority};
162 
163  FrameLib_Thread(PriorityLevel priority, ThreadFunctionType *threadFunction, void *arg)
164  : mInternal(nullptr), mPriority(priority), mThreadFunction(threadFunction), mArg(arg), mValid(false)
165  {}
166 
167  ~FrameLib_Thread();
168 
169  // Non-copyable
170 
171  FrameLib_Thread(const FrameLib_Thread&) = delete;
172  FrameLib_Thread& operator=(const FrameLib_Thread&) = delete;
173 
174  void start();
175  void join();
176 
177 private:
178 
179  // threadStart is a quick OS-style wrapper to call the object which calls the relevant static function
180 
181  static OS_Specific::OSThreadFunctionType threadStart;
182  void call() { mThreadFunction(mArg); }
183 
184  // Data
185 
186  OS_Specific::OSThreadType mInternal;
187  PriorityLevel mPriority;
188  ThreadFunctionType *mThreadFunction;
189  void *mArg;
190  bool mValid;
191 };
192 
193 
207 {
208 
209 public:
210 
211  FrameLib_Semaphore(long maxCount);
213 
214  // Non-copyable
215 
216  FrameLib_Semaphore(const FrameLib_Semaphore&) = delete;
217  FrameLib_Semaphore& operator=(const FrameLib_Semaphore&) = delete;
218 
219  void close();
220  void signal(long n);
221  bool wait();
222 
223 private:
224 
225  // Data
226 
228  bool mValid;
229 };
230 
231 
245 {
246 
247 public:
248 
249  FrameLib_TriggerableThread(FrameLib_Thread::PriorityLevel priority) : mThread(priority, threadEntry, this), mSemaphore(1) {}
251 
252  // Non-copyable
253 
255  FrameLib_TriggerableThread& operator=(const FrameLib_TriggerableThread&) = delete;
256 
257  // Start and join
258 
259  void start() { mThread.start(); }
260  void join();
261 
262  // Trigger the thread to do something
263 
264  void signal() { mSemaphore.signal(1); };
265 
266 private:
267 
268  // threadEntry simply calls threadClassEntry which calls the task handler
269 
270  static void threadEntry(void *thread);
271  void threadClassEntry();
272 
273  // Override this and provide code for the thread's functionality
274 
275  virtual void doTask() = 0;
276 
277  // Data
278 
279  FrameLib_Thread mThread;
280  FrameLib_Semaphore mSemaphore;
281 };
282 
283 
297 {
298 
299 public:
300 
301  FrameLib_DelegateThread(FrameLib_Thread::PriorityLevel priority) : mThread(priority, threadEntry, this), mSemaphore(1), mSignaled(false), mFlag(0) {}
303 
304  // Non-copyable
305 
307  FrameLib_DelegateThread& operator=(const FrameLib_DelegateThread&) = delete;
308 
309  // Start and join
310 
311  void start() { mThread.start(); }
312  void join();
313 
314  // Signal the thread to do something if it is not busy (returns true if the thread was signalled, false if busy)
315 
316  bool signal();
317 
318  // Wait for thread's completion of a task - returns true first time after a signal / false for subsequent calls/the thread has not been signalled
319 
320  bool completed();
321 
322 private:
323 
324  // threadEntry simply calls threadClassEntry which calls the task handler
325 
326  static void threadEntry(void *thread);
327  void threadClassEntry();
328 
329  // Override this and provide code for the thread's functionality
330 
331  virtual void doTask() = 0;
332 
333  // Data
334 
335  FrameLib_Thread mThread;
336  FrameLib_Semaphore mSemaphore;
337 
338  bool mSignaled;
339  std::atomic<int> mFlag;
340 };
341 
342 #endif
DWORD WINAPI OSThreadFunctionType(LPVOID arg)
Definition: FrameLib_Threading.h:53
PriorityLevel
Definition: FrameLib_Threading.h:161
a spinlock that can be locked, attempted or acquired.
Definition: FrameLib_Threading.h:84
void signal()
Definition: FrameLib_Threading.h:264
virtual ~FrameLib_DelegateThread()
Definition: FrameLib_Threading.h:302
bool compareAndSwap(std::atomic< T > &value, T comparand, T exchange)
Definition: FrameLib_Threading.h:61
FrameLib_SpinLockHolder(FrameLib_SpinLock *lock)
Definition: FrameLib_Threading.h:122
a RAII hold utility for a FrameLib_SpinLock
Definition: FrameLib_Threading.h:117
a thread that can be triggered from another thread (there is no mechanism to check progress) ...
Definition: FrameLib_Threading.h:244
virtual ~FrameLib_TriggerableThread()
Definition: FrameLib_Threading.h:250
bool attempt()
Definition: FrameLib_Threading.h:97
void start()
Definition: FrameLib_Threading.h:311
HANDLE OSSemaphoreType
Definition: FrameLib_Threading.h:52
FrameLib_Thread(PriorityLevel priority, ThreadFunctionType *threadFunction, void *arg)
Definition: FrameLib_Threading.h:163
bool nullSwap(std::atomic< T *> &value, T *exchange)
Definition: FrameLib_Threading.h:67
HANDLE OSThreadType
Definition: FrameLib_Threading.h:51
void release()
Definition: FrameLib_Threading.h:99
Definition: FrameLib_Threading.h:49
void start()
Definition: FrameLib_Threading.h:259
a semaphore class wrapping an OS-level semaphore
Definition: FrameLib_Threading.h:206
lightweight joinable thread with variable priority level
Definition: FrameLib_Threading.h:155
void destroy()
Definition: FrameLib_Threading.h:130
~FrameLib_SpinLockHolder()
Definition: FrameLib_Threading.h:123
FrameLib_SpinLock()
Definition: FrameLib_Threading.h:89
FrameLib_TriggerableThread(FrameLib_Thread::PriorityLevel priority)
Definition: FrameLib_Threading.h:249
~FrameLib_SpinLock()
Definition: FrameLib_Threading.h:90
void acquire()
Definition: FrameLib_Threading.h:98
FrameLib_DelegateThread(FrameLib_Thread::PriorityLevel priority)
Definition: FrameLib_Threading.h:301
a thread to delegate tasks to, which can be then be checked for completion
Definition: FrameLib_Threading.h:296